package org.hbhk.hxl.gateway.redis;

import java.util.List;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hbhk.hxl.gateway.boot.ApplicationContextUtil;
import org.hbhk.hxl.gateway.route.JsonUtil;
import org.redisson.Redisson;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;

import com.google.common.collect.Lists;
import com.google.common.util.concurrent.RateLimiter;

/**
 * **************************************************
 * 
 * @description redis工具类，底层使用redisson
 * 
 */
public class RedisUtil {

	private static final Log log = LogFactory.getLog(RedisUtil.class);

	private static final String DISTRIBUTED_LOCK_FLAG = "lock_";

	private static volatile RedissonClient redisson;

	public static RedissonClient getRedissonManager() {
		if (redisson == null) {
			synchronized (DISTRIBUTED_LOCK_FLAG) {
				if (redisson == null) {
					try {
						redisson = ApplicationContextUtil.getApplicationContext().getBean(RedissonClient.class);

					} catch (Exception e) {
						log.error("redis缓存错误", e);

					}

				}
			}
		}
		return redisson;
	}

	public static RedissonClient setRedissonManager(RedissonClient redissonManager) {
		RedisUtil.redisson = redissonManager;
		return redissonManager;
	}

	public static void lock(String lockname, long leaseTime, TimeUnit unit) {
		String key = DISTRIBUTED_LOCK_FLAG + lockname;
		RLock lock = getRedissonManager().getLock(key);
		// lock提供带timeout参数，timeout结束强制解锁，防止死锁 ：1分钟
		lock.lock(leaseTime, unit);
	}

	public static void publish(String topic, String json) {
		RTopic rTopic = getRedissonManager().getTopic(topic);
		rTopic.publish(json);
	}

	public static void unlock(String lockname) {
		String key = DISTRIBUTED_LOCK_FLAG + lockname;
		RLock lock = getRedissonManager().getLock(key);
		lock.unlock();
	}

	public static void lock(String lockname) {
		String key = DISTRIBUTED_LOCK_FLAG + lockname;
		RLock lock = getRedissonManager().getLock(key);
		// lock提供带timeout参数，timeout结束强制解锁，防止死锁 ：1分钟
		lock.lock(1, TimeUnit.MINUTES);
	}

	/**
	 * 从Redis获取key为name的数据，并封装为指定class实例，可能发生运行时异常
	 *
	 * @param <T>   泛型支持
	 * @param clazz
	 * @param name
	 * @return
	 */
	public static <T> T get(Class<T> clazz, String name) {

		RBucket<byte[]> keyObject = getRedissonManager().getBucket(name);
		byte[] bytes = keyObject.get();
		if (bytes == null) {
			return null;
		}
		return JsonUtil.deserialize(keyObject.get(), clazz);
	}

	/**
	 * 根据name清除数据
	 *
	 * @param name
	 */
	public static void remove(String name) {

		getRedissonManager().getBucket(name).delete();
	}

	/**
	 * 缓存数据到Redis,无超时
	 *
	 * @param name
	 * @param value
	 */
	public static void put(String name, Object value) {

		RBucket<byte[]> keyObject = getRedissonManager().getBucket(name);
		keyObject.set(JsonUtil.serialize(value));
	}

	/**
	 * 缓存数据到Redis
	 *
	 * @param name
	 * @param value
	 * @param timeToLive
	 * @param timeUnit
	 */
	public static void put(String name, Object value, long timeToLive, TimeUnit timeUnit) {

		RBucket<byte[]> keyObject = getRedissonManager().getBucket(name);
		keyObject.set(JsonUtil.serialize(value), timeToLive, timeUnit);
	}

	/**
	 * 按分钟（计算超时）缓存数据
	 *
	 * @param name
	 * @param value
	 * @param timeToLive
	 */
	public static void putCacheWithMinutes(String name, Object value, long timeToLive) {

		RBucket<byte[]> keyObject = getRedissonManager().getBucket(name);
		keyObject.set(JsonUtil.serialize(value), timeToLive, TimeUnit.MINUTES);
	}

	public static void main(String[] args) {
		Config config = new Config();
		SingleServerConfig serversConfig = config.useSingleServer().setAddress("redis://1.116.80.36:8888");
		serversConfig.setPassword("aa123456");
		redisson = Redisson.create(config);

		RateLimiter rateLimiter = RateLimiter.create(1);
		put("keyBytes", Lists.newArrayList("1", "2"));

		put("rateLimiter", rateLimiter);

		List<String> list = get(List.class, "keyBytes");

		rateLimiter = get(RateLimiter.class, "rateLimiter");

		System.out.println(list);

		redisson.shutdown();
	}

}
